package edu.se.jai.lesson04guess2.service;

import edu.se.jai.lesson04guess2.model.GameStatus;
import edu.se.jai.lesson04guess2.model.Result;
import edu.se.jai.lesson04guess2.model.entity.GameRoom;
import edu.se.jai.lesson04guess2.model.entity.Player;
import edu.se.jai.lesson04guess2.model.GuessResultData;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 房间管理服务类
 * 
 * 负责管理房间的核心业务逻辑，使用四个核心缓存：
 * - roomIdToRoom: 存储房间ID到房间的映射
 * - sessionIdToPlayer: 存储会话ID到玩家的映射
 * - sessionIdToRoomId: 存储会话ID到所在房间ID的映射
 */
@Slf4j
@Service
public class GameService {

    /** 每个房间最大玩家数 */
    @Value("${game.max-players-per-room:8}")
    private int maxPlayersPerRoom;

    /**
     * 存储所有游戏房间
     * Key: 房间ID, Value: 游戏房间对象
     */
    private final Map<String, GameRoom> roomIdToRoom = new ConcurrentHashMap<>();

    /**
     * 存储会话ID到玩家的映射
     * Key: 会话ID, Value: 玩家对象
     */
    private final Map<String, Player> sessionIdToPlayer = new ConcurrentHashMap<>();

    /**
     * 存储玩家所在的房间
     * Key: 会话ID, Value: 房间ID
     */
    private final Map<String, String> sessionIdToRoomId = new ConcurrentHashMap<>();



    /**
     * 注册玩家会话
     * 
     * @param sessionId 会话ID
     * @param playerName 玩家名称
     * @return 注册结果
     */
    public Result<String> registerPlayerSession(String sessionId, String playerName) {
        // 检查玩家名是否重复
        boolean nameExists = sessionIdToPlayer.values().stream()
                .anyMatch(player -> player.getName().equals(playerName));

        if (nameExists) {
            return Result.failure("玩家名称已存在，请选择其他名称");
        }

        // 创建玩家并注册会话
        Player player = createPlayer(playerName, sessionId);
        sessionIdToPlayer.put(sessionId, player);

        log.info("玩家 {} 会话注册成功，Session ID: {}", playerName, sessionId);
        return Result.success(playerName);
    }


    /**
     * 创建新房间
     * 
     * @param sessionId 创建者的会话ID
     * @return 创建结果
     */
    public Result<GameRoom> createRoom(String sessionId) {
        // 检查玩家是否已经加入了其他房间
        if (sessionIdToRoomId.containsKey(sessionId)) {
            return Result.failure("您已经加入了其他房间，不能创建新房间");
        }

        // 创建房间对象
        String roomId = generateRoomId();
        GameRoom room = new GameRoom();
        room.setRoomId(roomId);
        room.setCreatorSessionId(sessionId);
        room.setStatus(GameStatus.WAITING);
        room.setTargetNumber(generateTargetNumber());

        // 创建者自动加入房间
        Player creator = sessionIdToPlayer.get(sessionId);
        if (creator == null) {
            return Result.failure("玩家信息不存在");
        }
        
        room.getPlayers().put(sessionId, creator);
        roomIdToRoom.put(roomId, room);
        sessionIdToRoomId.put(sessionId, roomId);

        log.info("创建新房间: {}，创建者: {}", roomId, creator.getName());
        return Result.success(room);
    }

    /**
     * 加入房间
     * 
     * @param sessionId 玩家会话ID
     * @param roomId 房间ID
     * @return 加入结果
     */
    public Result<GameRoom> joinRoom(String sessionId, String roomId) {
        // 检查玩家是否已经加入了其他房间
        if (sessionIdToRoomId.containsKey(sessionId)) {
            return Result.failure("您已经加入了其他房间，不能加入更多房间");
        }
        
        // 获取房间信息
        GameRoom room = roomIdToRoom.get(roomId);
        if (room == null) {
            return Result.failure("房间不存在");
        }

        // 获取玩家信息
        Player player = sessionIdToPlayer.get(sessionId);
        if (player == null) {
            return Result.failure("玩家信息不存在");
        }

        // 检查房间是否已满
        if (room.getPlayers().size() >= maxPlayersPerRoom) {
            return Result.failure("房间已满");
        }
        
        // 检查房间状态，只有WAITING状态才能加入
        if (room.getStatus() != GameStatus.WAITING) {
            return Result.failure("游戏已开始，无法加入");
        }

        // 将玩家加入房间
        room.getPlayers().put(sessionId, player);
        sessionIdToRoomId.put(sessionId, roomId);

        log.info("玩家 {} 加入房间 {}", player.getName(), roomId);
        return Result.success(room);
    }

    /**
     * 离开房间
     * 
     * @param sessionId 玩家会话ID
     * @param roomId 房间ID
     * @return 离开结果
     */
    public Result<GameRoom> leaveRoom(String sessionId, String roomId) {
        // 1. 根据roomId获取房间对象
        GameRoom room = roomIdToRoom.get(roomId);
        if (room == null) {
            return Result.failure("房间不存在");
        }

        // 2. 验证玩家是否为房间创建者
        if (room.getCreatorSessionId().equals(sessionId)) {
            return Result.failure("房间创建者不能离开房间");
        }

        // 3.从房间中移除玩家
        Player player = room.getPlayers().remove(sessionId);

        // 4. 清理玩家的sessionIdToRoomId映射
        sessionIdToRoomId.remove(sessionId);


        log.info("玩家 {} 离开房间 {}", player.getName(), roomId);

        return Result.success(room);
    }

    /**
     * 解散房间
     * 
     * @param sessionId 解散者的会话ID
     * @param roomId 房间ID
     * @return 解散结果
     */
    public Result<GameRoom> dissolveRoom(String sessionId, String roomId) {
        // 1. 根据roomId获取房间对象
        GameRoom room = roomIdToRoom.get(roomId);
        if (room == null) {
            return Result.failure("房间不存在");
        }

        // 2. 验证玩家是否为房间创建者
        if (!room.getCreatorSessionId().equals(sessionId)) {
            return Result.failure("只有房间创建者才能解散房间");
        }

        // 3. 清理所有房间内玩家的sessionIdToRoomId映射
        for (String playerSessionId : room.getPlayers().keySet()) {
            sessionIdToRoomId.remove(playerSessionId);
        }

        // 4. 从roomIdToRoom中移除房间
        roomIdToRoom.remove(roomId);

        log.info("房间 {} 已被创建者解散，移除了 {} 个玩家的房间映射", roomId, room.getPlayers().size());

        return Result.success(room);
    }

    /**
     * 获取所有房间列表
     * 
     * @return 所有房间列表
     */
    public List<GameRoom> getAllRooms() {
        return new ArrayList<>(roomIdToRoom.values());
    }

    /**
     * 根据会话ID获取所在房间
     * 
     * @param sessionId 会话ID
     * @return 房间对象，如果不存在则返回null
     */
    public GameRoom getRoomBySessionId(String sessionId) {
        String roomId = sessionIdToRoomId.get(sessionId);
        if (roomId != null) {
            return roomIdToRoom.get(roomId);
        }
        return null;
    }

    /**
     * 根据会话ID获取玩家信息
     * 
     * @param sessionId 会话ID
     * @return 玩家对象，如果不存在则返回null
     */
    public Player getPlayerBySessionId(String sessionId) {
        return sessionIdToPlayer.get(sessionId);
    }


    // ==================== 游戏逻辑方法 ====================
    
    /**
     * 开始游戏
     * 
     * @param sessionId 创建者的会话ID
     * @param roomId 房间ID
     * @return 开始游戏结果
     */
    public Result<GameRoom> startGame(String sessionId, String roomId) {
        // 获取房间信息
        GameRoom room = roomIdToRoom.get(roomId);
        if (room == null) {
            return Result.failure("房间不存在");
        }

        // 验证是否为房间创建者
        if (!room.getCreatorSessionId().equals(sessionId)) {
            return Result.failure("只有房间创建者才能开始游戏");
        }

        // 检查房间状态
        if (room.getStatus() != GameStatus.WAITING) {
            return Result.failure("游戏状态不正确，无法开始游戏");
        }

        // 检查房间人数
        if (room.getPlayers().size() < 2) {
            return Result.failure("至少需要2个玩家才能开始游戏");
        }

        // 生成新的目标数字
        room.setTargetNumber(generateTargetNumber());
        room.setStatus(GameStatus.PLAYING);
        
        // 重置所有玩家的猜测状态
        for (Player player : room.getPlayers().values()) {
            player.setHasGuessed(false);
            player.setGuess(null);
            player.setGuessResult(null);
        }

        log.info("房间 {} 开始游戏，目标数字: {}", roomId, room.getTargetNumber());
        return Result.success(room);
    }

    /**
     * 停止游戏
     * 
     * @param sessionId 创建者的会话ID
     * @param roomId 房间ID
     * @return 停止游戏结果
     */
    public Result<GameRoom> stopGame(String sessionId, String roomId) {
        // 获取房间信息
        GameRoom room = roomIdToRoom.get(roomId);
        if (room == null) {
            return Result.failure("房间不存在");
        }

        // 验证是否为房间创建者
        if (!room.getCreatorSessionId().equals(sessionId)) {
            return Result.failure("只有房间创建者才能停止游戏");
        }

        // 检查房间状态
        if (room.getStatus() != GameStatus.PLAYING) {
            return Result.failure("游戏未在进行中，无法停止");
        }

        // 停止游戏
        room.setStatus(GameStatus.WAITING);
        
        // 重置所有玩家的猜测状态
        for (Player player : room.getPlayers().values()) {
            player.setHasGuessed(false);
            player.setGuess(null);
            player.setGuessResult(null);
        }

        log.info("房间 {} 停止游戏", roomId);
        return Result.success(room);
    }

    /**
     * 玩家猜测数字
     * 
     * @param sessionId 玩家会话ID
     * @param roomId 房间ID
     * @param guess 猜测的数字
     * @return 猜测结果
     */
    public Result<GuessResultData> makeGuess(String sessionId, String roomId, Integer guess) {

        // 1.获取房间信息并验证房间是否存在
        // 2.检查房间状态是否为PLAYING
        // 3.验证猜测数字范围
        // 4.获取玩家信息并验证玩家是否在房间中
        // 5.检查玩家是否已经猜对了（防止重复猜测）
        // 6. 记录玩家的猜测数字
        // 7. 判断猜测结果：
        //    - 如果 guess == targetNumber：猜对了
        //    - 如果 guess < targetNumber：猜小了
        //    - 如果 guess > targetNumber：猜大了
        // 8. 更新玩家状态
        // 9. 构建并返回GuessResultData对象


        // 1.获取房间信息并验证房间是否存在


        // 2.检查房间状态是否为PLAYING


        // 3.验证猜测数字范围


        // 4.获取玩家信息并验证玩家是否在房间中


        // 5.检查玩家是否已经猜对了（防止重复猜测）


        // 6. 记录玩家的猜测数字


        // 7.判断猜测结果
        // 8.更新玩家状态
//        Integer targetNumber = room.getTargetNumber();
//        boolean result;
//        String hint;
//
//        if (guess.equals(targetNumber)) {
//            result = true;
//            hint = "恭喜您猜对了！";
//            player.setGuessResult("正确");
//            // 猜对了，该玩家不能再猜测
//        } else if (guess < targetNumber) {
//            result = false;
//            hint = "您猜的数字太小了";
//            player.setGuessResult("错误");
//            // 猜错了，该玩家可以继续猜测
//        } else {
//            result = false;
//            hint = "您猜的数字太大了";
//            player.setGuessResult("错误");
//            // 猜错了，该玩家可以继续猜测
//        }

        // 9.构建返回结果
//        GuessResultData resultData = new GuessResultData(
//            roomId,
//            player.getName(),
//            guess,
//            result,
//            hint
//        );

        //log.info("玩家 {} 在房间 {} 中猜测数字 {}，结果: {}", player.getName(), roomId, guess, result);
        //return Result.success(resultData);
        return null;
    }

    // ==================== 基础工具方法 ====================
    
    /**
     * 创建玩家对象
     * 
     * @param name 玩家名称
     * @param sessionId 会话ID
     * @return 玩家对象
     */
    private Player createPlayer(String name, String sessionId) {
        Player player = new Player();
        player.setName(name);
        player.setSessionId(sessionId);
        return player;
    }

    /**
     * 生成目标数字（1-100）
     * 注意：当前为游戏功能预留，实际未使用
     * 
     * @return 1-100之间的随机数
     */
    private Integer generateTargetNumber() {
        return new Random().nextInt(100) + 1;
    }

    /**
     * 生成房间ID
     * 格式：room_时间戳_随机数
     * 
     * @return 唯一的房间ID
     */
    private String generateRoomId() {
        return "room_" + System.currentTimeMillis() + "_" + (int)(Math.random() * 1000);
    }
}